﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GalaSoft.MvvmLight;
using System.Drawing;
using ExifLib;


namespace PPP.Model {
    /// <summary>
    /// Picture model with all infomation. 
    /// 
    /// <list type="bullet">
    /// <item>
    /// <term>Author</term>
    /// <description>Sebastian Will</description>
    /// </item>
    /// </list>
    /// 
    /// </summary>
    public class Picture : ObservableObject {

        #region Fields
        private Image _thumbnail = null;
        private string _fileName = String.Empty;
        private long _fileSize = long.MinValue;
        private DateTime _lastModified = DateTime.MinValue;
        private FileInfo _fileInfo = null;
        private PictureProperties _pictureProperties = null;
        

        private Uri _pictureUri = null;//new Uri("pack://application:,,/Images/property-blue.png");//("https://www.google.de/images/srpr/logo11w.png");
        #endregion

        #region PropertyName Consts

        /// <summary>
        /// The <see cref="FileInfo" /> property's name.
        /// </summary>
        public const string FileInfoPropertyName = "FileInfo";

        /// <summary>
        /// The <see cref="FileName" /> property's name.
        /// </summary>
        public const string FileNamePropertyName = "FileName";

        /// <summary>
        /// The <see cref="FileSize" /> property's name.
        /// </summary>
        public const string FileSizePropertyName = "FileSize";

        /// <summary>
        /// The <see cref="LastModified" /> property's name.
        /// </summary>
        public const string LastModifiedPropertyName = "LastModified";

        /// <summary>
        /// The <see cref="Metadata" /> property's name.
        /// </summary>
        public const string MetadataPropertyName = "Metadata";

        /// <summary>
        /// The <see cref="PictureProperties" /> property's name.
        /// </summary>
        public const string PicturePropertiesPropertyName = "PictureProperties";
        
        
        #endregion

        #region Properties
        
        public Image Thumbnail {
            get {
                return _thumbnail;
            }

            set {
                if (_thumbnail == value) {
                    return;
                }
                _thumbnail = value;
                RaisePropertyChanged(FileInfoPropertyName);
            }
        }

        /// <summary>
        /// Sets and gets the FileInfo property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public FileInfo FileInfo {
            get {
                return _fileInfo;
            }

            set {
                if (_fileInfo == value) {
                    return;
                }
                _fileInfo = value;
                RaisePropertyChanged(FileInfoPropertyName);
            }
        }

        /// <summary>
        /// Sets and gets the Metadata property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public PictureProperties PictureProperties {
            get {
                return _pictureProperties;
            }

            set {
                if (_pictureProperties == value) {
                    return;
                }
                _pictureProperties = value;
                RaisePropertyChanged(PicturePropertiesPropertyName);
            }
        }
              
        /// <summary>
        /// Sets and gets the FileName property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string FileName {
            get {
                return _fileName;
            }

            set {
                if (_fileName == value) {
                    return;
                }

                RaisePropertyChanging(FileNamePropertyName);
                _fileName = value;
                RaisePropertyChanged(FileNamePropertyName);
            }
        }

        /// <summary>
        /// Sets and gets the FileName property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public long FileSize {
            get {
                return _fileSize;
            }

            set {
                if (_fileSize == value) {
                    return;
                }

                RaisePropertyChanging(FileSizePropertyName);
                _fileSize = value;
                RaisePropertyChanged(FileSizePropertyName);
            }
        }

        /// <summary>
        /// Sets and gets the FileName property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public DateTime LastModified {
            get {
                return _lastModified;
            }

            set {
                if (_lastModified == value) {
                    return;
                }

                RaisePropertyChanging(LastModifiedPropertyName);
                _lastModified = value;
                RaisePropertyChanged(LastModifiedPropertyName);
            }
        }

        public Uri PictureUri {
            get {
                return _pictureUri;
            }

            set {
                if (_pictureUri == value) {
                    return;
                }


                _pictureUri = value;
                
            }
        }

        #endregion

        #region Constructors


        public Picture(FileInfo fileInfo)
        {

            _pictureUri = new Uri(fileInfo.FullName);
            _fileInfo = fileInfo;


            try {
                using (var reader = new ExifReader(fileInfo.FullName)) {
                    // Get the image thumbnail (if present)
                    var thumbnailBytes = reader.GetJpegThumbnailBytes();

                    if (thumbnailBytes == null)
                        _thumbnail = null;
                    else {
                        using (var stream = new MemoryStream(thumbnailBytes))
                            _thumbnail = Image.FromStream(stream);
                    }

                    // To read a single field, use code like this:
                    /*
                    DateTime datePictureTaken;
                    if (reader.GetTagValue(ExifTags.DateTimeDigitized, out datePictureTaken))
                    {
                        MessageBox.Show(this, string.Format("The picture was taken on {0}", datePictureTaken), "Image information", MessageBoxButtons.OK);
                    }
                    */

                    // Parse through all available fields and generate key-value labels
                    var properties = Enum.GetValues(typeof(ExifTags)).Cast<ushort>().Select(tagID => {
                        object val;
                        if (reader.GetTagValue(tagID, out val)) {
                            // Special case - some doubles are encoded as TIFF rationals. These
                            // items can be retrieved as 2 element arrays of {numerator, denominator}
                            if (val is double) {
                                int[] rational;
                                if (reader.GetTagValue(tagID, out rational))
                                    val = string.Format("{0} ({1}/{2})", val, rational[0], rational[1]);
                            }

                            return new KeyValuePair<string, string>(Enum.GetName(typeof(ExifTags), tagID), RenderTag(val)); //string.Format("{0}: {1}", Enum.GetName(typeof(ExifTags), tagID), RenderTag(val));
                        }

                        return new KeyValuePair<string, string>(Enum.GetName(typeof(ExifTags), tagID), string.Empty);

                    }).Where(x => x.Key != null).ToArray();


                    Dictionary<string, string> propertiesDictionary = properties.ToDictionary((keyItem) => keyItem.Key, (valueItem) => valueItem.Value);
                    
                    _pictureProperties = new PictureProperties(propertiesDictionary);
                }
            }
            catch (Exception ex) {
            }
            


            
           
        
        }
       
        #endregion

        #region Methods

        private static string RenderTag(object tagValue) {
            // Arrays don't render well without assistance.
            var array = tagValue as Array;
            if (array != null) {
                // Hex rendering for really big byte arrays (ugly otherwise)
                if (array.Length > 20 && array.GetType().GetElementType() == typeof(byte))
                    return "0x" + string.Join("", array.Cast<byte>().Select(x => x.ToString("X2")).ToArray());

                return string.Join(", ", array.Cast<object>().Select(x => x.ToString()).ToArray());
            }

            return tagValue.ToString();
        }

        #endregion

    }
}
